
package JET.physics.engine;

import JET.geom.Vec2d;
import JET.physics.CollisionType;
import JET.physics.Mass;
import JET.physics.MassMBCollision;
import JET.physics.bodies.RigidBody;
import JET.physics.bodies.SpringBody;
import java.util.Collection;

/**
 *
 * @author raos
 */
public class JETEngine {

    public static void performSimulationStep(JETContext c) {

        Collection<SpringBody> sbCol = c.getSpringBodyListSync();
        synchronized(sbCol) {
            for(SpringBody sb : sbCol) {
                sb.simulate(c.dTime);
                sb.updateBoundingArea();
            }
        }

        Collection<RigidBody> rbCol = c.getRigidBodyListSync();
        synchronized(rbCol) {
            for(RigidBody rb : rbCol) {
                rb.simulate(c.dTime);
                rb.updateBoundingArea();
            }
        }

         c.time +=  c.dTime;
    }
    public static void checkCollisions(JETContext c) {
        collisionsCheck_Mass2d_MainBound(c);

        c.sbColInfoCount = 0;
        c.rbColInfoCount = 0;

        SBCollider.collisionCheck_SpringBodies(c);

        RBCollider.zeroSeparationVecs(c);
        RBCollider.collisionCheck_RigidBodies(c);
    }

    public static void handleCollisions(JETContext c) {
        SBCollider.handleCollisions(c);
        RBCollider.handleCollisions(c);
        collisionsAnswer_Mass2d_MainBound(c);
    }

    public static void collisionsCheck_Mass2d_MainBound(JETContext c) {
        c.m2dmbColList.clear();

        Collection<SpringBody> sbCol = c.getSpringBodyListSync();
        synchronized(sbCol) {
            for(SpringBody sb : sbCol) {
                Collection<Mass> massCol = sb.getMassListSync();
                synchronized(massCol) {
                    for (Mass mass : massCol)
                        if ( mass.isMoveable() ) {
                            if ( mass.getPosition().getX() < c.mainBound.getX() ) {
                                MassMBCollision mmbC = new MassMBCollision(CollisionType.OUTOFBOUND_LEFT, mass, sb);
                                c.m2dmbColList.add( mmbC );
                            }
                            else if ( mass.getPosition().getX() > c.mainBound.getMaxX() ) {
                                MassMBCollision mmbC = new MassMBCollision(CollisionType.OUTOFBOUND_RIGHT, mass, sb);
                                c.m2dmbColList.add( mmbC );
                            }

                            if ( mass.getPosition().getY() < c.mainBound.getY() ) {
                                MassMBCollision mmbC = new MassMBCollision(CollisionType.OUTOFBOUND_TOP, mass, sb);
                                c.m2dmbColList.add( mmbC );
                            }
                            if ( mass.getPosition().getY() > c.mainBound.getMaxY() ) {
                                MassMBCollision mmbC = new MassMBCollision(CollisionType.OUTOFBOUND_BOTTOM, mass, sb);
                                c.m2dmbColList.add( mmbC );
                            }
                        }
                }
            }
        }
    }

    public static void collisionsAnswer_Mass2d_MainBound(JETContext c) {
        for (int i=0; i<c.m2dmbColList.size(); i++)
        {
            SpringBody sb = c.m2dmbColList.get(i).sb;
            Mass mass =  c.m2dmbColList.get(i).mass2d;
            double bounce = c.materials[sb.getMaterial()][c.mainBoundMaterial].elasticity;
            double friction = c.materials[sb.getMaterial()][c.mainBoundMaterial].friction;

            if (c.materials[sb.getMaterial()][c.mainBoundMaterial].collide)
                switch( c.m2dmbColList.get(i).cType )
                {
                    case OUTOFBOUND_LEFT :
                        mass.getPosition().setX( c.mainBound.getX() );
                        mass.getVelocity().setX( -1* mass.getVelocity().getX() * bounce );
                        mass.getVelocity().setY( mass.getVelocity().getY() * (1-friction) );
                        break;
                    case OUTOFBOUND_RIGHT :
                        mass.getPosition().setX( c.mainBound.getMaxX()  );
                        mass.getVelocity().setX( -1* mass.getVelocity().getX() * bounce );
                        mass.getVelocity().setY( mass.getVelocity().getY() * (1-friction) );
                        break;
                    case OUTOFBOUND_TOP :
                        mass.getPosition().setY( c.mainBound.getY()  );
                        mass.getVelocity().setY( -1* mass.getVelocity().getY() *bounce );
                        mass.getVelocity().setX( mass.getVelocity().getX() * (1-friction) );
                        break;
                    case OUTOFBOUND_BOTTOM :
                        mass.getPosition().setY( c.mainBound.getMaxY()  );
                        mass.getVelocity().setY( -1* mass.getVelocity().getY() * bounce );
                        mass.getVelocity().setX( mass.getVelocity().getX() * (1-friction) );
                        break;
                }
        }
    }

    //------------------------ Weird stuff ---------------------------
    public static void zeroMass2dVelocities(JETContext c) {
        Collection<SpringBody> sbCol = c.getSpringBodyListSync();
        synchronized(sbCol) {
            for (SpringBody sb : sbCol) {
                Collection<Mass> massCol = sb.getMassListSync();
                synchronized(massCol) {
                    for (Mass mass : massCol)
                        mass.getVelocity().zero();
                }
            }
        }
    }
    public static void randomMass2dVelocities(JETContext c) {
        Collection<SpringBody> sbCol = c.getSpringBodyListSync();
        synchronized(sbCol) {
            for (SpringBody sb : sbCol) {
                Collection<Mass> massCol = sb.getMassListSync();
                synchronized(massCol) {
                    for (Mass mass : massCol) {
                        Vec2d random = Vec2d.getRandomVectorInCircle(100);
                        mass.setVelocity( random );
                    }
                }
            }
        }
    }

//    public void notifyJavaScriptOfCollisions(JETContext c) {
//        ScriptsCenter SC = c.scene.SC;
//        //for(int i=0; i<sbColInfoList.size(); i++) {
//        for(int i=0; i<c.sbColInfoCount; i++) {
//            SBCollision col = c.sbColInfoList.get(i);
//            SC.notifyOnBodyCollision(col, i);
//        }
//    }

}
